//#include <iostream>
//#include <vector>
//using namespace std;
//
//int n, k;
//vector<int> path;
//bool st[15] = { 0 };
//
//void dfs()
//{
//	if (path.size() == k)
//	{
//		for (auto ch : path)
//		{
//			cout << ch << " ";
//		}
//		cout << endl;
//		
//		return;
//	}
//
//	for (int i = 1; i <= n; i++)
//	{
//		if (st[i] == 0)
//		{
//			path.push_back(i);
//			st[i] = 1;
//			dfs();
//			st[i] = 0;
//			path.pop_back();
//		}
//	}
//}
//
//int main()
//{
//	cin >> n >> k;
//	for (int i = 1; i <= n; i++)
//	{
//		path.push_back(i);
//		st[i] = 1;
//		dfs();
//		st[i] = 0;
//		path.pop_back();
//	}
//	return 0;
//}


//#include <iostream>
//#include <vector>
//using namespace std;
//
//const int N = 15;
//
//vector<int> path;
//int t[N] = { 0 };
//int d[N] = { 0 };
//int l[N] = { 0 };
//int st[N] = { 0 };
//
//int T, n;
//int cnt = 0;
//
//bool dfs(int tt)
//{
//	if (cnt == n)
//	{
//		return 1;
//	}
//
//	for (int i = 1; i <= n; i++)
//	{
//		if (tt > t[i] + d[i])
//			continue;
//		if (st[i] == 0)
//		{
//			cnt++;
//			st[i] = 1;
//			if (dfs(max(tt, t[i]) + l[i]))
//				return 1;
//			st[i] = 0;
//			cnt--;
//		}
//	}
//
//	return 0;
//}
//
//int main()
//{
//	cin >> T;
//	while (T--)
//	{
//		cnt = 0;
//		cin >> n;
//		for (int i = 1; i <= n; i++)
//		{
//			cin >> t[i] >> d[i] >> l[i];
//			st[i] = 0;
//		}
//
//		if (dfs(0))
//			cout << "YES" << endl;
//		else
//			cout << "NO" << endl;
//	}
//	return 0;
//}


//#include <iostream>
//#include <queue>
//#include <cstring>
//using namespace std;
//
//const int N = 1e5 + 10;
//
//int T;
//int x, y;
//
//int st[N] = { 0 };
//
//void bfs()
//{
//	queue<int> q;
//	q.push(x);
//	st[x] = 0;
//
//	while (q.size())
//	{
//		int t = q.front();
//		q.pop();
//		
//		if (t + 1 <= 1e5 + 10 && st[t + 1] == 0)
//		{
//			st[t + 1] = st[t] + 1;
//			if (t + 1 == y)
//				return;
//
//			q.push(t + 1);
//		}
//
//		if (st[t - 1] == 0)
//		{
//			st[t - 1] = st[t] + 1;
//			if (t - 1 == y)
//				return;
//			q.push(t - 1);
//		}
//
//		if (2 * t <= 1e5 + 10 && st[t * 2] == 0)
//		{
//			st[t * 2] = st[t] + 1;
//			if (t * 2 == y)
//				return;
//			q.push(t * 2);
//		}
//		
//	}
//}
//
//int main()
//{
//	cin >> T;
//	while (T--)
//	{
//		memset(st, 0, sizeof(st));
//		cin >> x >> y;
//		bfs();
//		cout << st[y] << endl;
//	}
//
//	return 0;
//}



#include <iostream>
#include <queue>
#include <cstring>
using namespace std;

const int N = 1010;

int dx[] = { 0, 0, 1, -1 };
int dy[] = { -1, 1, 0, 0 };

int f[N][N] = { 0 };
bool st[N][N] = { 0 };

int n, m;

bool bfs(int num)
{
	queue<pair<int, int>> q;
	memset(st, 0, sizeof(st));
	for (int i = 1; i <= m; i++)
	{
		q.push({ 1, i });
		st[1][i] = 1;
	}

	while (q.size())
	{
		auto ch = q.front();
		q.pop();
		int x = ch.first;
		int y = ch.second;

		for (int k = 0; k < 4; k++)
		{
			int i = x + dx[k];
			int j = y + dy[k];
			
			if (i >= 1 && i <= n && j >= 1 && j <= m && st[i][j] == 0 && f[i][j] <= num)
			{
				st[i][j] = 1;
				q.push({ i, j });
				if (i == n)
					return 1;
			}
		}
	}

	return 0;
}

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			cin >> f[i][j];
		}
	}

	int l = 0;
	int r = 1000;

	while (l < r)
	{
		int mid = (l + r) / 2;
		if (bfs(mid))
		{
			r = mid;
		}
		else
		{
			l = mid + 1;
		}
	}

	cout << l << endl;

	return 0;
}
